/*
 * Copyright the original author or authors.
 * 
 * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *	  http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.googlecode.milib.animation.static_ {
	import com.googlecode.milib.animation.static_.AnimationDistance;
	import com.googlecode.milib.animation.static_.AnimationElement;
	import com.googlecode.milib.animation.static_.ObjectAnimations;
	import com.googlecode.milib.base.MLWorkClass;
	import com.googlecode.milib.data.value.MLNumberValue;

	public class Animation extends MLWorkClass {
		
		public var event_Update:String='Update';
		
		private var elements : Array;
		public var name : String;
		private var animTimeUnit : AnimationDistance;
		private var easeForAll:MLEase;
		public var animOut:Animation;

		public function Animation(time:uint=1000, name:String=null){
			elements=[];
			this.name=name;
			setupWorkingTime(time);
			//_global.pl.milib.anim.dbg.AnimationsDBG.getInstance().regAnim(this);
		}//<>
		
		public function setupEaseForAll(ease:MLEase):void {
			easeForAll=ease;
			for(var i:uint=0,ele:AnimationElement;i<elements.length;i++){
				ele=elements[i];
				ele.ease=ease;
			}
		}
		
		public function addElement(obj:Object, param:String, target:Number, ease:MLEase=null):AnimationElement {
			if(easeForAll && ease==null) { ease=easeForAll; }
			return addElementByInstance(new AnimationElement(obj, param, target, ease));
		}
		public function addElements(elementsArguments:Array, ease:MLEase):void {
			for(var i:uint=0,elementArguments:Array;i<elementsArguments.length;i++){
				elementArguments=elementsArguments[i];
				if(!elementArguments[3]){ elementArguments[3]=ease; }
				addElement.apply(this, elementArguments);
			}
		}
		public function addElementByInstance(aei:AnimationElement):AnimationElement {
			ObjectAnimations.forInstance(aei.obj).regAnimation(this);
			elements.push(aei);
			return aei;
		}
		
		public function getElements():Array {
			return elements.concat();
		}
		
		public function setupDistanceUnit(animTimeUnit:AnimationDistance):void {
			this.animTimeUnit=animTimeUnit;
		}
		public function setupDistanceUnitByElement(aei:AnimationElement):void {
			animTimeUnit=new AnimationDistance(aei);
		}
		
		override public function getWorkingTime():Number {
			if(animTimeUnit){
				return animTimeUnit.getTime(super.getWorkingTime());
			}else{
				return super.getWorkingTime();
			}
		}
		
		public function addElementsFromAnimation(anim:Animation, isTargetsAsCurrents:Boolean):void {
			var eles:Array=anim.getElements();
			for(var i:uint=0;i<eles.length;i++){
				if(isTargetsAsCurrents){
					addElementByInstance(AnimationElement(eles[i]).cloneByTargetAsCurrent());
				}else{
					addElementByInstance(AnimationElement(eles[i]).clone());
				}
			}
		}
		
		public function addElementsFromAnimations(anims:Array, isTargetsAsCurrents:Boolean):void {
			for(var i:uint=0;i<anims.length;i++){
				addElementsFromAnimation(anims[i], isTargetsAsCurrents);
			}
		}
		
		override protected function doStart():Boolean {
			for(var i:uint=0,aei:AnimationElement;aei=elements[i];i++){
				if(isNaN(aei.target)){ 
					throw new Error('Can\'t start animation because one AnimationElement ('+aei.param+') have NaN \'target\'');
				}
				ObjectAnimations.forInstance(aei.obj).regRunningAnimationElement(aei);
				aei.setRunningInAnimation(this);
				aei.reset();
			}
			return super.doStart();
		}
		
		override protected function doWork():void {
			var progress:Number=getProgress();
			for(var i:uint=0,aei:AnimationElement;aei=elements[i];i++){
				aei.applyN01(progress);
			}
			broadcastEvent(event_Update);
		}
		
		override protected function doFinish():Boolean {
			if(super.doFinish()){
				for(var i:uint=0,aei:AnimationElement;aei=elements[i];i++){
					ObjectAnimations.forInstance(aei.obj).unregRunningAnimationElement(aei);
					if(isSuccess){
						aei.applyTargetParam();
					}
				}
				broadcastEvent(event_Update);
				return true;
			}
			return false;
		}
		
		public function cloneByTargetsAsCurrents(isMirrorEase:Boolean=false, name:String=null):Animation {
			var anim:Animation=new Animation(NaN, name);
			if(workingTimeDN){ anim.setupWorkingTimeAsDynamicNumber(workingTimeDN); }
			else if(workingTime){ anim.setupWorkingTime(workingTime); }
			for(var i:uint=0,aei:AnimationElement;aei=elements[i];i++){
				anim.addElementByInstance(aei.cloneByTargetAsCurrent(isMirrorEase));
			} 
			return anim;
		}
		
		public function cloneByNewObject(newObject:Object, name:String=null):Animation {
			var anim:Animation=new Animation(NaN, name);
			if(workingTimeDN){ anim.setupWorkingTimeAsDynamicNumber(workingTimeDN); }
			else if(workingTime){ anim.setupWorkingTime(workingTime); }
			for(var i:uint=0,aei:AnimationElement;aei=elements[i];i++){
				anim.addElementByInstance(aei.cloneByNewObject(newObject));
			} 
			return anim;
		}
		
		public function clonesByNewObjects(newObjects:Array, prefixName:String=null):Array {
			var anims:Array=[];
			var namePrefix:String=prefixName==null ? '' : prefixName;
			if(name){ namePrefix=name+namePrefix; }
			for(var i:uint=0,newObject:Object;i<newObjects.length;i++){
				newObject=newObjects[i];
				anims.push(cloneByNewObject(newObject, namePrefix+i));
			}
			return anims;
		}
		
//		private function getDBGInfo():Array {
//			var infoText:Array=[];
//			infoText.push('Animation elements: (object, variable name, ease)');
//			for(var i:uint=0,element:AnimationElement;i<elements.length;i++){
//				element=elements[i];
//				infoText.push('	'+link(element.obj)+', '+element.param+', '+link(element.ease));
//			}
//			
//			return [infoText.join('\n')+'\n'].concat(super.getDBGInfo());;
//		}
		
		public function getFirstObj():Object {
			return elements[0].obj;
		}
		
		public function setNewTargetByParam(param:String, target:Number):void {
			for(var i:uint=0,animationsElement:AnimationElement;i<elements.length;i++){
				animationsElement=elements[i];
				if(animationsElement.param==param){
					animationsElement.target=target;
				}
			}
		}
		
		public static function createNewDynamicForID(id:String):Animation {
			var anim:Animation=new Animation();
			anim.setupEaseForAll(MLEase.getInstanceForName(id));			anim.setupWorkingTimeAsDynamicNumber(MLNumberValue.getInstanceForID(id));
			return anim;
		}
	}
	
}